//
// Created by XUAN on 2024/8/23.
//

#include "blufi_app.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cJSON.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED
#include "esp_bt.h"
#endif
#include <nimble/nimble_port.h>

#include "esp_blufi_api.h"
#include "esp_blufi.h"
#include "nvs_operation.h"
#include "webConfigServer.h"
#include "webDnsConfig.h"
#include "audio_tone_uri.h"

#define EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY 5
#define EXAMPLE_INVALID_REASON                255
#define EXAMPLE_INVALID_RSSI                  -128

static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);

#define WIFI_LIST_NUM   10

static wifi_config_t sta_config;
static wifi_config_t ap_config;

/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;

/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
const int CONNECTED_BIT = BIT0;

static uint8_t example_wifi_retry = 0;

/* store the station info for send back to phone */
bool gl_sta_connected = false;
bool gl_sta_got_ip = false;
static bool ble_is_connected = false;
static uint8_t gl_sta_bssid[6];
static uint8_t gl_sta_ssid[32];
static int gl_sta_ssid_len;
static wifi_sta_list_t gl_sta_list;
static bool gl_sta_is_connecting = false;
static esp_blufi_extra_info_t gl_sta_conn_info;

/*---------------------------parameters------------------------------*/
static const char *TAG = "BLUFI_WIFI";

bool blufi_Wifi_connected = false;
bool web_Wifi_connected = false;
bool wifi_connected = false;
char *nvs_wifi_list = NULL;

bool blufi_start_flag = false;

char* scan_wifi_list = NULL;

extern TaskHandle_t blufiAPPTaskHandle;
static bool wifi_config_done = false;

bool blufi_task_del_state = false;

/*------------------------------------------------------------------*/

/*-----------------------------main---------------------------------*/
extern char BT_MAC[35];
/*------------------------------------------------------------------*/

/*-----------------------------webConfigServer-----------------------------*/
extern TaskHandle_t webServerTaskHandle;
extern TaskHandle_t webSocketTaskHandle;
/*-------------------------------------------------------------------------*/

/*-----------------------------webDnsConfig--------------------------------*/
extern TaskHandle_t webDnsConfigTaskHandle;
/*-------------------------------------------------------------------------*/
// 写入更新后的 Wi-Fi 列表到 NVS
bool update_nvs_wifi_list(const char *new_ssid, const char *new_pass)
{
    cJSON *json = NULL;
    int last_index = 0;

    ESP_LOGI(TAG, "将连接的WiFi名称进行存储");
    ESP_LOGI(TAG, "nvs_wifi_list: %s", nvs_wifi_list);
    ESP_LOGI(TAG, "nvs_wifi_list length: %d", strlen(nvs_wifi_list));

    // 检查 nvs_wifi_list 是否为空或无效
    if (nvs_wifi_list == NULL || strlen(nvs_wifi_list) == 0 || nvs_wifi_list[0] != '{')
    {
        // 初始化一个新的 JSON 对象
        json = cJSON_CreateObject();
        if (json == NULL)
        {
            ESP_LOGE(TAG, "[update_nvs_wifi_list] Failed to create JSON object!");
            return false;
        }

        // 初始化 last 字段
        last_index = 1;
        cJSON_AddStringToObject(json, "last", "1");

        // 添加新的 WiFi 信息
        cJSON *new_wifi = cJSON_CreateObject();
        cJSON_AddStringToObject(new_wifi, "SSID", new_ssid);
        cJSON_AddStringToObject(new_wifi, "PASS", new_pass);
        cJSON_AddItemToObject(json, "1", new_wifi);
        ESP_LOGI(TAG,">>>>>>>>>>>>>>>>>>new json");
    }
    else
    {
        // 解析现有的 nvs_wifi_list
        json = cJSON_Parse(nvs_wifi_list);
        if (json == NULL)
        {
            ESP_LOGE(TAG, "[update_nvs_wifi_list] Failed to parse JSON string!");
            return false;
        }

        // 获取当前的 last 索引
        cJSON *last_item = cJSON_GetObjectItem(json, "last");
        ESP_LOGI(TAG,">>>>>>>>>>>>>>>>> last item : %s", last_item->valuestring);
        if (last_item && cJSON_IsString(last_item))
        {
            last_index = atoi(last_item->valuestring);
        }
        else
        {
            last_index = 0;
        }

        // 计算现有 Wi-Fi 信息数量
        int wifi_count = 0;
        char index_str[12];
        // 遍历 JSON 对象，获取有效的 Wi-Fi 条目数量
        cJSON *current_item = NULL;
        cJSON_ArrayForEach(current_item, json)
        {
            if (cJSON_IsObject(current_item) && cJSON_GetObjectItem(current_item, "SSID"))
            {
                wifi_count++;
            }
        }
        ESP_LOGI(TAG, "wifi_count: %d", wifi_count);

        int found = 0;
        for (int i = 1; i <= wifi_count; i++)
        {
            snprintf(index_str, sizeof(index_str), "%d", i);
            cJSON *wifi_item = cJSON_GetObjectItem(json, index_str);
            if (wifi_item)
            {
                cJSON *ssid_item = cJSON_GetObjectItem(wifi_item, "SSID");
                ESP_LOGI(TAG,">>>>>>>>>>>>>>>>>wifi_item: %s", ssid_item->valuestring);
                if (ssid_item && strcmp(ssid_item->valuestring, new_ssid) == 0)
                {
                    found = 1;
                    // 只更新 last 字段
                    cJSON_ReplaceItemInObject(json, "last", cJSON_CreateString(index_str));
                    cJSON_ReplaceItemInObject(wifi_item, "PASS", cJSON_CreateString(new_pass));
                    break;
                }
            }
        }

        if (!found)
        {
            // 如果没有找到相同的 SSID，新增一个条目
            last_index = wifi_count + 1; //更新 last_index 为新条目数量
            snprintf(index_str, sizeof(index_str), "%d", last_index);

            cJSON *new_wifi = cJSON_CreateObject();
            cJSON_AddStringToObject(new_wifi, "SSID", new_ssid);
            cJSON_AddStringToObject(new_wifi, "PASS", new_pass);
            cJSON_AddItemToObject(json, index_str, new_wifi);

            // 更新 last 字段
            cJSON_ReplaceItemInObject(json, "last", cJSON_CreateString(index_str));
        }
    }

    // 将更新后的 JSON 转为字符串
    char *updated_wifi_list = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);

    // 将字符串写入 NVS
    bool result = nvs_write_wifi_list(updated_wifi_list);

    ESP_LOGI(TAG, "Updated wifi_list: %s", updated_wifi_list);
    free(updated_wifi_list);
    return result;
}
static void example_record_wifi_conn_info(int rssi, uint8_t reason)
{
    memset(&gl_sta_conn_info, 0, sizeof(esp_blufi_extra_info_t));
    if (gl_sta_is_connecting) {
        gl_sta_conn_info.sta_max_conn_retry_set = true;
        gl_sta_conn_info.sta_max_conn_retry = EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY;
    } else {
        gl_sta_conn_info.sta_conn_rssi_set = true;
        gl_sta_conn_info.sta_conn_rssi = rssi;
        gl_sta_conn_info.sta_conn_end_reason_set = true;
        gl_sta_conn_info.sta_conn_end_reason = reason;
    }
}

static void example_wifi_connect(void)
{
    example_wifi_retry = 0;
    gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
    example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
}

static bool example_wifi_reconnect(void)
{
    bool ret;
    if (gl_sta_is_connecting && example_wifi_retry++ < EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY) {
        BLUFI_INFO("BLUFI WiFi starts reconnection\n");
        gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
        example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
        ret = true;
    } else {
        ret = false;
    }
    return ret;
}

static int softap_get_current_connection_number(void)
{
    esp_err_t ret;
    ret = esp_wifi_ap_get_sta_list(&gl_sta_list);
    if (ret == ESP_OK)
    {
        return gl_sta_list.num;
    }

    return 0;
}

static void ip_event_handler(void* arg, esp_event_base_t event_base,
                             int32_t event_id, void* event_data)
{
    wifi_mode_t mode;

    switch (event_id) {
        case IP_EVENT_STA_GOT_IP: {
            if (ble_is_connected == true)
            {
                uint8_t *conn = (uint8_t *)malloc(100);
                char upload_blufi_info[100] = {0};
                sprintf(upload_blufi_info, "{\"wifi\":\"connected\"}");
                for (size_t i = 0; i < strlen(upload_blufi_info); i++)
                {
                    conn[i] = upload_blufi_info[i];
                }
                esp_blufi_send_custom_data(conn, strlen(upload_blufi_info));
                free(conn); // 释放内存
            }

            esp_blufi_extra_info_t info;

            xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
            esp_wifi_get_mode(&mode);

            memset(&info, 0, sizeof(esp_blufi_extra_info_t));
            memcpy(info.sta_bssid, gl_sta_bssid, 6);
            info.sta_bssid_set = true;
            info.sta_ssid = gl_sta_ssid;
            info.sta_ssid_len = gl_sta_ssid_len;
            gl_sta_got_ip = true;
            if (ble_is_connected == true) {
                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_get_current_connection_number(), &info);
            } else {
                BLUFI_INFO("BLUFI BLE is not connected yet\n");
            }

            if(blufi_start_flag) {
                play_tone(WIFI_OK);
            }
            handleWiFiConnected_TASK_DEL();
            break;
        }
        default:
            break;
    }
    return;
}


void handleWiFiConnected_TASK_DEL() {

    // 释放分配的内存
    if (nvs_wifi_list != NULL) {
        heap_caps_free(nvs_wifi_list);
        nvs_wifi_list = NULL;
        ESP_LOGI(TAG, "nvs_wifi_list memory freed.");
    }

    if (scan_wifi_list != NULL) {
        heap_caps_free(scan_wifi_list);
        scan_wifi_list = NULL;
        ESP_LOGI(TAG, "scan_wifi_list memory freed.");
    }

    // 检查并删除 webServerTaskHandle
    if (webServerTaskHandle != NULL)
    {
        // 挂起任务，防止其在删除时继续运行
        vTaskSuspend(webServerTaskHandle);
        // 通知任务结束
        xTaskNotifyGive(webServerTaskHandle);
        // 等待一小段时间让任务完成清理工作
        vTaskDelay(pdMS_TO_TICKS(100));
        // 删除任务
        vTaskDelete(webServerTaskHandle);
        // 将句柄设置为 NULL
        webServerTaskHandle = NULL;

        ESP_LOGI(TAG, "Web Server task stopped and deleted.");
    }

    // // 检查并删除 webSocketTaskHandle
    // if (webSocketTaskHandle != NULL)
    // {
    //     vTaskSuspend(webSocketTaskHandle);
    //     xTaskNotifyGive(webSocketTaskHandle);
    //     vTaskDelay(pdMS_TO_TICKS(100));
    //     vTaskDelete(webSocketTaskHandle);
    //     webSocketTaskHandle = NULL;
    //     ESP_LOGI(TAG, "Web Socket task stopped and deleted.");
    // }

    // 检查并删除 webDnsConfigTaskHandle
    if (webDnsConfigTaskHandle != NULL)
    {
        vTaskSuspend(webDnsConfigTaskHandle);
        xTaskNotifyGive(webDnsConfigTaskHandle);
        vTaskDelay(pdMS_TO_TICKS(100));
        vTaskDelete(webDnsConfigTaskHandle);
        webDnsConfigTaskHandle = NULL;
        ESP_LOGI(TAG, "DNS Server task stopped and deleted.");
    }

    if (blufi_start_flag) {
        // 重置配网标志
        blufi_start_flag = false;
        // 停止 BLUFI 广播
        esp_blufi_adv_stop();
        ESP_LOGI(TAG, "BLUFI advertising stopped.");

        // 反初始化 BLUFI 配置文件
        esp_blufi_profile_deinit();
        ESP_LOGI(TAG, "BLUFI profile deinitialized.");
#if CONFIG_BT_BLUEDROID_ENABLED
        // 停止并反初始化蓝牙控制器 (Bluedroid)
        esp_bluedroid_disable();
        esp_bluedroid_deinit();

        esp_bt_controller_disable();
        esp_bt_controller_deinit();
        ESP_LOGI(TAG, "Bluetooth controller disabled and deinitialized.");
#elif CONFIG_BT_NIMBLE_ENABLED
        // 停止并反初始化蓝牙控制器 (NimBLE)
        nimble_port_stop();
        nimble_port_deinit();

        esp_err_t ret = esp_bt_controller_disable();
        if (ret) {
            ESP_LOGE(TAG, "Bluetooth controller disable failed: %s", esp_err_to_name(ret));
        } else {
            ESP_LOGI(TAG, "Bluetooth controller disabled.");
        }

        ret = esp_bt_controller_deinit();
        if (ret) {
            ESP_LOGE(TAG, "Bluetooth controller deinit failed: %s", esp_err_to_name(ret));
        } else {
            ESP_LOGI(TAG, "Bluetooth controller deinitialized.");
        }
#endif

        // 将 Wi-Fi 模式切换回 STA 模式
        esp_wifi_set_mode(WIFI_MODE_STA);
        ESP_LOGI(TAG, "Wi-Fi mode set to STA.");

    }


    ESP_LOGI(TAG, "All Wi-Fi configuration tasks and resources have been cleaned up.");

    blufi_task_del_state = true;
}

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    wifi_event_sta_connected_t *event;
    wifi_event_sta_disconnected_t *disconnected_event;
    wifi_mode_t mode;

    switch (event_id) {
        case WIFI_EVENT_STA_START:
//            example_wifi_connect();
            wifi_config_done = false;  // 重置 WiFi 配置状态
            break;
        case WIFI_EVENT_STA_CONNECTED:
            gl_sta_connected = true;
            gl_sta_is_connecting = false;

            wifi_config_done = true;  // 设置标志

            event = (wifi_event_sta_connected_t*) event_data;
            memcpy(gl_sta_bssid, event->bssid, 6);
            memcpy(gl_sta_ssid, event->ssid, event->ssid_len);
            gl_sta_ssid_len = event->ssid_len;

            wifi_config_t sta_config;
            esp_wifi_get_config(WIFI_IF_STA, &sta_config);
            // 更新 NVS 中的 Wi-Fi 列表
            update_nvs_wifi_list((char *)gl_sta_ssid, (char *)sta_config.sta.password);
            ESP_LOGI(TAG, "Connected to SSID %s SUCCESS", gl_sta_ssid);

            break;
        case WIFI_EVENT_STA_DISCONNECTED:
            /* Only handle reconnection during connecting */
            if (gl_sta_connected == false && example_wifi_reconnect() == false) {
                gl_sta_is_connecting = false;
                disconnected_event = (wifi_event_sta_disconnected_t*) event_data;
                example_record_wifi_conn_info(disconnected_event->rssi, disconnected_event->reason);
            }
            /* This is a workaround as ESP32 WiFi libs don't currently
               auto-reassociate. */

            ESP_LOGW(TAG, "Wi-Fi disconnected, reason: %d", ((wifi_event_sta_disconnected_t*)event_data)->reason);

            gl_sta_connected = false;
            gl_sta_got_ip = false;
            memset(gl_sta_ssid, 0, 32);
            memset(gl_sta_bssid, 0, 6);
            gl_sta_ssid_len = 0;
            xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
            break;
        case WIFI_EVENT_AP_START:
            esp_wifi_get_mode(&mode);

            /* TODO: get config or information of softap, then set to report extra_info */
            if (ble_is_connected == true) {
                if (gl_sta_connected) {
                    esp_blufi_extra_info_t info;
                    memset(&info, 0, sizeof(esp_blufi_extra_info_t));
                    memcpy(info.sta_bssid, gl_sta_bssid, 6);
                    info.sta_bssid_set = true;
                    info.sta_ssid = gl_sta_ssid;
                    info.sta_ssid_len = gl_sta_ssid_len;
                    esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
                } else if (gl_sta_is_connecting) {
                    esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
                } else {
                    esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
                }
            } else {
                BLUFI_INFO("BLUFI BLE is not connected yet\n");
            }
            break;
        case WIFI_EVENT_SCAN_DONE: {
            ESP_LOGI(TAG, "WIFI_EVENT_SCAN_DONE");
            uint16_t apCount = 0;
            esp_wifi_scan_get_ap_num(&apCount);
            if (apCount == 0) {
                BLUFI_INFO("Nothing AP found");
                break;
            }
            wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
            if (!ap_list) {
                BLUFI_ERROR("malloc error, ap_list is NULL");
                esp_wifi_clear_ap_list();
                break;
            }
            ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
            esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));
            if (!blufi_ap_list) {
                if (ap_list) {
                    free(ap_list);
                }
                BLUFI_ERROR("malloc error, blufi_ap_list is NULL");
                break;
            }
            cJSON *scan_json = cJSON_CreateArray();
            //打印apCount
            ESP_LOGI(TAG, "apCount: %d", apCount);
            for (int i = 0; i < apCount; ++i)
            {
                blufi_ap_list[i].rssi = ap_list[i].rssi;
                memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
                BLUFI_INFO("[scan_wifi_list] SSID: %s, RSSI: %d", (char *)ap_list[i].ssid, ap_list[i].rssi);
                cJSON *ap_json = cJSON_CreateObject();
                cJSON_AddStringToObject(ap_json, "SSID", (const char *)ap_list[i].ssid);
                cJSON_AddNumberToObject(ap_json, "RSSI", ap_list[i].rssi);
                cJSON_AddItemToArray(scan_json, ap_json);
            }
            scan_wifi_list = cJSON_PrintUnformatted(scan_json);
            cJSON_Delete(scan_json);
            //打印scan_wifi_list
            ESP_LOGI(TAG, "scan_wifi_list: %s", scan_wifi_list);

            if (ble_is_connected == true) {
                esp_blufi_send_wifi_list(apCount, blufi_ap_list);
            } else {
                BLUFI_INFO("BLUFI BLE is not connected yet\n");
            }

            esp_wifi_scan_stop();
            free(ap_list);
            free(blufi_ap_list);
            break;
        }
        case WIFI_EVENT_AP_STACONNECTED: {
            wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
            BLUFI_INFO("station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid);
            break;
        }
        case WIFI_EVENT_AP_STADISCONNECTED: {
            wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
            BLUFI_INFO("station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid);
            break;
        }

        default:
            break;
    }
    return;
}

static void initialise_wifi(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
    ESP_ERROR_CHECK( esp_wifi_start() );
}

static esp_blufi_callbacks_t example_callbacks = {
        .event_cb = example_event_callback,
        .negotiate_data_handler = blufi_dh_negotiate_data_handler,
        .encrypt_func = blufi_aes_encrypt,
        .decrypt_func = blufi_aes_decrypt,
        .checksum_func = blufi_crc_checksum,
};
#include "host/ble_gap.h"
#include "esp_log.h"

// 这个函数用于处理 GAP 事件
static int gap_event(struct ble_gap_event *event, void *arg) {
    switch (event->type) {
        case BLE_GAP_EVENT_CONNECT:
            // 当建立连接或连接失败时调用
            if (event->connect.status == 0) {
                ESP_LOGI("GAP", "连接成功");
            } else {
                ESP_LOGI("GAP", "连接失败，状态=%d", event->connect.status);
                // 如果连接失败，重新启动广播
                ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                                  (struct ble_gap_adv_params *)arg, gap_event, NULL);
            }
            break;

        case BLE_GAP_EVENT_DISCONNECT:
            // 当断开连接时调用，重新启动广播
            ESP_LOGI("GAP", "断开连接，原因=%d", event->disconnect.reason);
            ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                              (struct ble_gap_adv_params *)arg, gap_event, NULL);
            break;

        case BLE_GAP_EVENT_ADV_COMPLETE:
            // 广播完成时调用，重新启动广播
            ESP_LOGI("GAP", "广播完成，重新启动");
            ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                              (struct ble_gap_adv_params *)arg, gap_event, NULL);
            break;

        case BLE_GAP_EVENT_SUBSCRIBE:
            // 当客户端订阅或取消订阅通知时调用
            ESP_LOGI("GAP", "订阅事件");
            break;

        default:
            break;
    }
    return 0;
}

static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
    /* actually, should post to blufi_task handle the procedure,
     * now, as a example, we do it more simply */
    switch (event) {
        case ESP_BLUFI_EVENT_INIT_FINISH:
            BLUFI_INFO("BLUFI init finish\n");
             uint8_t derived_mac_addr[6] = {0};
             ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_BT));

             char device_name[20] = {0};
             sprintf(device_name, "AiSpea_%02x%02x", derived_mac_addr[4], derived_mac_addr[5]);

             // 设置设备名称
             struct ble_hs_adv_fields fields;
             memset(&fields, 0, sizeof(fields));
             fields.name = (uint8_t *)device_name;
             fields.name_len = strlen(device_name);
             fields.name_is_complete = 1;

             int rc = ble_gap_adv_set_fields(&fields);
             if (rc != 0) {
                 printf("Error setting advertisement data; rc=%d\n", rc);
             }

             // 配置广播参数并启动广播
             struct ble_gap_adv_params adv_params;
             memset(&adv_params, 0, sizeof(adv_params));
             adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
             adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;

             rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, gap_event, NULL);
             if (rc != 0) {
                 printf("Error enabling advertisement; rc=%d\n", rc);
             }
            esp_blufi_adv_start();
            break;
        case ESP_BLUFI_EVENT_DEINIT_FINISH:
            BLUFI_INFO("BLUFI deinit finish\n");
            break;
        case ESP_BLUFI_EVENT_BLE_CONNECT:
            BLUFI_INFO("BLUFI ble connect\n");
            ble_is_connected = true;
            esp_blufi_adv_stop();
            blufi_security_init();
            break;
        case ESP_BLUFI_EVENT_BLE_DISCONNECT:
            BLUFI_INFO("BLUFI ble disconnect\n");
            ble_is_connected = false;
            blufi_security_deinit();
            if(blufi_start_flag) {
                esp_blufi_adv_start();
            }
            break;
        case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
            BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
            ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) );
            break;
        case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
            BLUFI_INFO("BLUFI requset wifi connect to AP\n");
            wifi_config_done = false;  // 重置 WiFi 配置状态

            /* there is no wifi callback when the device has already connected to this wifi
            so disconnect wifi before connection.
            */
            esp_wifi_disconnect();
            example_wifi_connect();
            break;
        case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
            BLUFI_INFO("BLUFI requset wifi disconnect from AP\n");
            esp_wifi_disconnect();
            break;
        case ESP_BLUFI_EVENT_REPORT_ERROR:
            BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state);
            esp_blufi_send_error_info(param->report_error.state);
            break;
        case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {
            wifi_mode_t mode;
            esp_blufi_extra_info_t info;

            esp_wifi_get_mode(&mode);

            if (gl_sta_connected) {
                memset(&info, 0, sizeof(esp_blufi_extra_info_t));
                memcpy(info.sta_bssid, gl_sta_bssid, 6);
                info.sta_bssid_set = true;
                info.sta_ssid = gl_sta_ssid;
                info.sta_ssid_len = gl_sta_ssid_len;
                esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
            } else if (gl_sta_is_connecting) {
                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
            } else {
                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
            }
            BLUFI_INFO("BLUFI get wifi status from AP\n");

            break;
        }
        case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
            BLUFI_INFO("blufi close a gatt connection");
            esp_blufi_disconnect();
            break;
        case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
            /* TODO */
            break;
        case ESP_BLUFI_EVENT_RECV_STA_BSSID:
            memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
            sta_config.sta.bssid_set = 1;
            esp_wifi_set_config(WIFI_IF_STA, &sta_config);
            BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid);
            break;
        case ESP_BLUFI_EVENT_RECV_STA_SSID:
            strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
            sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
            esp_wifi_set_config(WIFI_IF_STA, &sta_config);
            BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid);
            wifi_config_done = false;  // 重置 WiFi 配置状态
            break;
        case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
            strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
            sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
            // 准备发送给设备的 JSON 数据
            char upload_blufi_info[100] = {0};
            sprintf(upload_blufi_info, "{\\\"status\\\":\\\"ok\\\",\\\"device_serial\\\":\\\"%s\\\"}", BT_MAC);

            // 分配内存用于发送
            uint8_t *conn = (uint8_t *)malloc(strlen(upload_blufi_info) + 1);
            if (conn != NULL)
            {
                memcpy(conn, upload_blufi_info, strlen(upload_blufi_info) + 1);

                // 发送自定义数据到设备端
                esp_err_t err = esp_blufi_send_custom_data(conn, strlen(upload_blufi_info));
                BLUFI_INFO("BLUFI send custom data  %d\n", err);

                // 释放内存
                free(conn);
            }
            /*返回数据给手机app，告知连接完成*/
            ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA)); // 切换到AP_STA模式

            esp_wifi_set_config(WIFI_IF_STA, &sta_config);
            BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password);
//            rec_blufi_time = xTaskGetTickCount();
            wifi_config_done = false;  // 重置 WiFi 配置状态

            break;
        case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
            strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len);
            ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0';
            ap_config.ap.ssid_len = param->softap_ssid.ssid_len;
            esp_wifi_set_config(WIFI_IF_AP, &ap_config);
            BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len);
            break;
        case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
            strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len);
            ap_config.ap.password[param->softap_passwd.passwd_len] = '\0';
            esp_wifi_set_config(WIFI_IF_AP, &ap_config);
            BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len);
            break;
        case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
            if (param->softap_max_conn_num.max_conn_num > 4) {
                return;
            }
            ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num;
            esp_wifi_set_config(WIFI_IF_AP, &ap_config);
            BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection);
            break;
        case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
            if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) {
                return;
            }
            ap_config.ap.authmode = param->softap_auth_mode.auth_mode;
            esp_wifi_set_config(WIFI_IF_AP, &ap_config);
            BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode);
            break;
        case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
            if (param->softap_channel.channel > 13) {
                return;
            }
            ap_config.ap.channel = param->softap_channel.channel;
            esp_wifi_set_config(WIFI_IF_AP, &ap_config);
            BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel);
            break;
        case ESP_BLUFI_EVENT_GET_WIFI_LIST:{
            wifi_scan_config_t scanConf = {
                    .ssid = NULL,
                    .bssid = NULL,
                    .channel = 0,
                    .show_hidden = false
            };
            esp_err_t ret = esp_wifi_scan_start(&scanConf, true);
            if (ret != ESP_OK) {
                esp_blufi_send_error_info(ESP_BLUFI_WIFI_SCAN_FAIL);
            }
            break;
        }
        case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
            BLUFI_INFO("Recv Custom Data %" PRIu32 "\n", param->custom_data.data_len);
                    esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
            break;
        case ESP_BLUFI_EVENT_RECV_USERNAME:
            /* Not handle currently */
            break;
        case ESP_BLUFI_EVENT_RECV_CA_CERT:
            /* Not handle currently */
            break;
        case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
            /* Not handle currently */
            break;
        case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
            /* Not handle currently */
            break;
        case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
            /* Not handle currently */
            break;;
        case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
            /* Not handle currently */
            break;
        default:
            break;
    }
}

bool is_wifi_connected()
{
    wifi_ap_record_t ap_info;
    if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
        return true;
    } else {
        return false;
    }
}
/*
 * 链接最后一次链接的wifi
 * */
bool try_connect_last_wifi(){
    ESP_LOGI(TAG, "[try_connect_last_wifi] !!!!!!!!!!!!!!");
    cJSON *json = cJSON_Parse(nvs_wifi_list);
    if (json == NULL) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Failed to parse JSON string!");
        return false;
    }

    cJSON *last_item = cJSON_GetObjectItem(json, "last");
    if (last_item == NULL || !cJSON_IsString(last_item) || last_item->valuestring == NULL || strcmp(last_item->valuestring, "0") == 0) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Failed to get last WiFi index!");
        cJSON_Delete(json);
        return false;
    }

    cJSON *last_wifi = cJSON_GetObjectItem(json, last_item->valuestring);
    if (last_wifi == NULL || !cJSON_IsObject(last_wifi)) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Failed to get WiFi info for index %s!", last_item->valuestring);
        cJSON_Delete(json);
        return false;
    }

    cJSON *ssid_item = cJSON_GetObjectItem(last_wifi, "SSID");
    cJSON *pass_item = cJSON_GetObjectItem(last_wifi, "PASS");

    if (!cJSON_IsString(ssid_item) || !cJSON_IsString(pass_item)) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Invalid SSID or PASS format!");
        cJSON_Delete(json);
        return false;
    }

    wifi_config_t wifi_config_first = {};
    strncpy((char *)wifi_config_first.sta.ssid, ssid_item->valuestring, sizeof(wifi_config_first.sta.ssid) - 1);
    wifi_config_first.sta.ssid[sizeof(wifi_config_first.sta.ssid) - 1] = '\0';
    strncpy((char *)wifi_config_first.sta.password, pass_item->valuestring, sizeof(wifi_config_first.sta.password) - 1);
    wifi_config_first.sta.password[sizeof(wifi_config_first.sta.password) - 1] = '\0';

    cJSON_Delete(json);

    esp_err_t err = esp_wifi_stop();
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Failed to stop WiFi: %s", esp_err_to_name(err));
        return false;
    }

    ESP_LOGI(TAG, "[try_connect_last_wifi] Try to connect last WiFi: %s", wifi_config_first.sta.ssid);
    err = esp_wifi_set_config(WIFI_IF_STA, &wifi_config_first);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "[try_connect_last_wifi] Failed to set WiFi config: %s", esp_err_to_name(err));
        return false;
    }

    ESP_ERROR_CHECK(esp_wifi_start());
    vTaskDelay(pdMS_TO_TICKS(1000));
    esp_wifi_disconnect();
    vTaskDelay(500);
    esp_wifi_connect();


    int retry_count = 0;
    while (!is_wifi_connected() && retry_count < 6)
    {
        ESP_LOGI(TAG, "等待网络连接...");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        retry_count++;
    }
    if(is_wifi_connected()) {
        return true;
    }

    return false;
}
/*
 * 扫描环境WiFi后，与nvs存储的WiFi信息进行比对，如果有则直接连接
 * */
bool try_connect_to_scan_wifi() {
    ESP_LOGI(TAG, "[try_connect_to_scan_wifi] !!!!!!!!!!!!!!");
    esp_wifi_disconnect();
    vTaskDelay(pdMS_TO_TICKS(500));  // 等待500毫秒，确保断开完成
//    esp_wifi_scan_start(NULL, true);

    ESP_LOGI(TAG, "[try_connect_to_scan_wifi] 扫描完毕，开始比对WiFi列表");
    if (nvs_wifi_list == NULL || scan_wifi_list == NULL) {
        ESP_LOGE(TAG, "[try_connect_to_scan_wifi] WiFi list is NULL");
        return false;
    }

// 解析NVS中的Wi-Fi列表
    cJSON *nvs_json = cJSON_Parse(nvs_wifi_list);
    cJSON *scan_json = cJSON_Parse(scan_wifi_list);

    if (nvs_json == NULL || scan_json == NULL) {
        ESP_LOGE(TAG, "[try_connect_to_scan_wifi] Failed to parse JSON!");
        cJSON_Delete(nvs_json);
        cJSON_Delete(scan_json);
        return false;
    }

    // 检查 last 字段的值
    cJSON *last_item = cJSON_GetObjectItem(nvs_json, "last");
    if (last_item == NULL || strcmp(last_item->valuestring, "0") == 0) {
        ESP_LOGI(TAG, "[try_connect_to_scan_wifi] No WiFi entries available, skipping scan.");
        cJSON_Delete(nvs_json);
        return false;  // 跳过搜索配网
    }

    esp_err_t err = esp_wifi_scan_start(NULL, true);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Wi-Fi scan start failed: %s", esp_err_to_name(err));
        return false;
    }
    vTaskDelay(500);

    // 遍历扫描到的Wi-Fi列表
    cJSON *scan_item = NULL;
    cJSON_ArrayForEach(scan_item, scan_json) {
        if (scan_item == NULL) continue;
        const char *scan_ssid = cJSON_GetObjectItem(scan_item, "SSID")->valuestring;
        if (scan_ssid == NULL) continue;

        ESP_LOGI(TAG, "[try_connect_to_scan_wifi] Checking SSID: %s", scan_ssid);

        cJSON *nvs_item = NULL;

        // 在NVS存储的Wi-Fi列表中查找匹配的SSID
        cJSON_ArrayForEach(nvs_item, nvs_json) {
            if (nvs_item == NULL || !cJSON_IsObject(nvs_item)) continue;
            if (strcmp(nvs_item->string, "last") == 0) continue; // 跳过 "last" 项

            const char *nvs_ssid = cJSON_GetObjectItem(nvs_item, "SSID")->valuestring;
            const char *nvs_password = cJSON_GetObjectItem(nvs_item, "PASS")->valuestring;

            if (nvs_ssid == NULL || nvs_password == NULL) continue;


            if (strcmp(scan_ssid, nvs_ssid) == 0) {
                ESP_LOGI(TAG, "[try_connect_to_scan_wifi] Found matching SSID: %s", scan_ssid);

                // 尝试连接
                wifi_config_t wifi_config = {};
                strncpy((char *)wifi_config.sta.ssid, nvs_ssid, sizeof(wifi_config.sta.ssid) - 1);
                strncpy((char *)wifi_config.sta.password, nvs_password, sizeof(wifi_config.sta.password) - 1);

                ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
                ESP_ERROR_CHECK(esp_wifi_start());
                esp_wifi_connect();

                vTaskDelay(5000); // 等待4秒尝试连接

                wifi_ap_record_t ap_info;
                if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
                    ESP_LOGI(TAG, "[try_connect_to_scan_wifi] Connected to SSID: %s", scan_ssid);
                    cJSON_Delete(nvs_json);
                    cJSON_Delete(scan_json);
                    return true;
                } else {
                    ESP_LOGI(TAG, "[try_connect_to_scan_wifi] Failed to connect to SSID: %s", scan_ssid);
                }
            }
        }
    }

    // 如果没有找到匹配的SSID，或者连接失败
    cJSON_Delete(nvs_json);
    cJSON_Delete(scan_json);
    return false;
}

#define EXAMPLE_ESP_WIFI_CHANNEL (10)
#define EXAMPLE_MAX_STA_CONN (5)

#define EXAMPLE_ESP_WIFI_SSID "AiSpea_0123"
#define EXAMPLE_ESP_WIFI_PASS "12345678"

#define CONFIG_ESP_WIFI_AUTH_OPEN 1

static void ap_wifi_event_handler(void *arg, esp_event_base_t event_base,
                                  int32_t event_id, void *event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
        ESP_LOGI("ESP32", "station " MACSTR " join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
    else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
        ESP_LOGI("ESP32", "station " MACSTR " leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

void wifi_ap_init(){
    ESP_ERROR_CHECK(esp_wifi_stop());

    esp_netif_create_default_wifi_ap(); /*创建默认WIFI AP,如果出现任何初始化错误,此API将中止*/
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); /*初始化WiFi为WiFi驱动程序分配资源，如WiFi控制结构、RX/TX缓冲区、WiFi NVS结构等。此WiFi还启动WiFi任务。*/

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &ap_wifi_event_handler,
                                                        NULL,
                                                        NULL));
    char ap_name[32] = "AiSpea_";
    wifi_config_t wifi_config = {
            .ap = {
                    .ssid_len = 0,
                    .channel = EXAMPLE_ESP_WIFI_CHANNEL,
                    .password = "12345678",
                    .max_connection = EXAMPLE_MAX_STA_CONN,
                    .authmode = WIFI_AUTH_OPEN},
    };
    uint8_t derived_mac_addr[6] = {0};
    ESP_ERROR_CHECK(esp_read_mac(derived_mac_addr, ESP_MAC_BT));
    snprintf((char *)wifi_config.ap.ssid, sizeof(wifi_config.ap.ssid), "AiSpea_%02X%02X",derived_mac_addr[4], derived_mac_addr[5]);
    wifi_config.ap.ssid_len = strlen((char *)wifi_config.ap.ssid);

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI("ESP32", "%d-----wifi_init_softap finished. SSID:%s password:%s channel:%d     ssid:%s",
             strlen("AiSpea_0123"), EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL, ap_name);
}

void blufi_app_main(void *Parm)
{
    esp_err_t ret;
    nvs_wifi_list = (char *) heap_caps_malloc(1000, MALLOC_CAP_SPIRAM);
    scan_wifi_list = (char *) heap_caps_malloc(1600, MALLOC_CAP_SPIRAM);
    if(nvs_wifi_list == NULL){
        ESP_LOGE(TAG,"Memory for nvs_wifi_list is not enough");
        return;
    }
    if(nvs_read_wifi_list(nvs_wifi_list, 1000)){
        ESP_LOGI(TAG, "Read wifi_list from NVS: %s\n", nvs_wifi_list);
    }else{
        ESP_LOGE(TAG, "Read wifi_list from NVS failed\n");
    }
    ESP_LOGI(TAG, "nvs_wifi_list: %s", nvs_wifi_list);

    // 初始化 wifi_config_done
    wifi_config_done = false;

    initialise_wifi();

    if(try_connect_last_wifi()){
        wifi_connected = true;
        ESP_LOGI(TAG, "try_connect_last_wifi successful");
    } else{
        wifi_connected = false;
        ESP_LOGE(TAG, "try_connect_last_wifi failed");
    }
    if(wifi_connected) {
        vTaskDelete(blufiAPPTaskHandle);
    }
    if(try_connect_to_scan_wifi()){
        wifi_connected = true;
        ESP_LOGI(TAG, "try_connect_to_scan_wifi successful");
    } else{
        wifi_connected = false;
        ESP_LOGE(TAG, "try_connect_to_scan_wifi failed");
    }
    if(wifi_connected) {
        vTaskDelete(blufiAPPTaskHandle);
    }

    while (!gl_sta_connected){
        if(!blufi_start_flag){
            blufi_start_flag = true;

            // 重置 wifi_config_done
            wifi_config_done = false;

            esp_wifi_disconnect();
            vTaskDelay(500);

            esp_wifi_scan_start(NULL, true);

            /*开启web配网*/
            wifi_ap_init();
            dns_server_start();
            web_server_start();


#if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED
            ret = esp_blufi_controller_init();
            if (ret) {
                BLUFI_ERROR("%s BLUFI controller init failed: %s\n", __func__, esp_err_to_name(ret));
                return;
            }
#endif

            ret = esp_blufi_host_and_cb_init(&example_callbacks);
            if (ret) {
                BLUFI_ERROR("%s initialise failed: %s\n", __func__, esp_err_to_name(ret));
                return;
            }
            BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version());

            play_tone(WIFI_CONFIG);
        }
        vTaskDelay(500);
    }
    vTaskDelete(NULL);
}